home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1997 September / Macworld (1997-09).dmg / Shareware World / Utilities / Text Processing / Alpha / Tcl / SystemCode / procs.tcl < prev    next >
Text File  |  1997-03-28  |  34KB  |  1,339 lines

  1.  
  2. #==============================================================================
  3. # Load electric alias, rebind tcl file completion for precedence.
  4. proc loadElectricAlias {} {
  5.     global HOME
  6.     uplevel #0 {
  7.         source "$HOME:Tcl:ElectricAlias:electricAlias.tcl"
  8.     }
  9.     message "ElectricAlias loaded."
  10.     bind '\t' tclFileCompletion "Shel"
  11.     enableMenuItem -m install "Electric Alias" off
  12. }
  13.  
  14. proc debug {} {
  15.     uplevel #0 {
  16.         set debugging 1
  17.     }
  18. }
  19.  
  20.  
  21. proc normalLeftBracket {} {
  22.     insertText "\{"
  23. }
  24. proc normalRightBracket {} {
  25.     insertText "\}"
  26. }
  27. bind '\[' <zs>  normalLeftBracket
  28. bind '\]' <zs>  normalRightBracket
  29.             
  30. # Select the next or current word. If word already selected, will go to next.
  31. proc hiliteWord {} {
  32.     if {[getPos]!=[selEnd]}    forwardChar
  33.     forwardWord
  34.     set start [getPos]
  35.     backwardWord
  36.     select $start [getPos]
  37. }
  38. bind 'h' <z> hiliteWord
  39.  
  40. #================================================================================
  41. # Mode variables
  42. #================================================================================
  43. # For mark stack.
  44. set markName 0
  45. set markStack ""
  46.  
  47. # mapping of windows to current modes.
  48. set winModes("") ""
  49.  
  50. # making vars local to windows
  51. # 'incomingVars' used to hold old var values that have been overwritten in current window
  52.  
  53. #================================================================================
  54. # Handle 'flag' and 'var' menu selections.
  55. #================================================================================
  56. # proc editFlag {menu item} {
  57. #     global $item incomingVars localVars modifiedVars tcl_var_procs
  58. #     if {[regexp {\? (.*)} $item dummy var]} {
  59. #         alphaHelp
  60. #         eval select [search -f 1 -r 1 "^$var"]
  61. #         return
  62. #     }
  63. #     lappend modifiedVars $item
  64. #     set val [expr ([set $item]-1)*-1]
  65. #     markMenuItem $menu $item [expr ($val)?"on":"off"]
  66. #     set $item $val
  67. #     if {[info exists tcl_var_procs($item)]} {
  68. #         $tcl_var_procs($item) $item
  69. #     }
  70. # }
  71.  
  72. proc editVar {menu item} {
  73.     global $item incomingVars localVars modifiedVars
  74.  
  75.     if {[regexp {\? (.*)} $item dummy var]} {
  76.         alphaHelp
  77.         eval select [search -f 1 -r 1 "^$var"]
  78.         return
  79.     }
  80.     lappend modifiedVars $item
  81.     append prmpt "New Value of " $item ": "
  82.     if ![catch {prompt $prmpt [set $item]} res] {
  83.         set $item $res
  84.     }
  85. }
  86.  
  87.  
  88.  
  89.  
  90. #================================================================================
  91.  
  92. # Instantiate a global variable to the path of a file (usually an app). As a
  93. # side-effect, make the instantiation permanent.
  94. proc addAppPath {name var} {
  95.     global $var modifiedVars
  96.     
  97.     if {$name == "CodeWarrior Compiler"} {
  98.         alertnote {Please locate the compiler via menu item "Config:App Paths:CodeWarrior Compiler"}
  99.         error ""
  100.     } elseif {$name == "CodeWarrior Debugger"} {
  101.         alertnote {Please locate the debugger via menu item "Config:App Paths:CodeWarrior Debugger"}
  102.         error ""
  103.     }
  104.         
  105.     set $var [getfile "Find '$name' app:"]
  106.     lappend modifiedVars $var
  107. }
  108.  
  109.  
  110. proc getFileSig {f} {
  111.     getFileInfo $f arr
  112.     return $arr(creator)
  113. }
  114.  
  115. proc getFileType {f} {
  116.     getFileInfo $f arr
  117.     return $arr(type)
  118. }
  119.  
  120.  
  121. # Look for given app sig in active processes. If not there, try to 
  122. # launch with 'path' prompting for 'path' if necessary.
  123. # Return the real name of the app. Don't switch.
  124.  
  125. # Slightly modified version of 'checkRunning' that looks for any of a
  126. # list of running apps.  The name of the app is returned. 
  127. proc checkRunning {prompt sigs path {in_front 1}} {
  128.     global $path
  129.  
  130.     # See if a process w/ any of the acceptable sigs already running.
  131.     # If so, use it, whether it's the one specified by $path or not.
  132.     #
  133.     foreach proc [processes] {
  134.         # if a running app has the correct sig, ...
  135.         if {[lsearch -exact $sigs [lindex $proc 1]] >= 0} {
  136.             # ...then return its name.
  137.             return [lindex $proc 0]
  138.         }
  139.     }
  140.  
  141.     # If the path variable or the file it references don't exist,
  142.     # or if its sig isn't one that we expect, then prompt the user 
  143.     # to locate the app.
  144.     #
  145.     if {![info exists $path] || ![file exists [set $path]] 
  146.              || [lsearch -exact $sigs [getFileSig [set $path]]] < 0} {
  147.         if {[catch {addAppPath $prompt $path}]} return
  148.     }
  149.  
  150.     # Check that the user's choice has an acceptable sig
  151.     if {[lsearch -exact $sigs [getFileSig [set $path]]] < 0} {
  152.         unset $path
  153.         message "Inappropriate file chosen"
  154.         return {} 
  155.     }
  156.     
  157.     # Launch the app
  158.     if {$in_front} {
  159.         if {[catch {launch -f [set $path]}]} {
  160.             error "Problem with launching file (out of memory?)"
  161.         }
  162.     } else {
  163.         if {[catch {launch [set $path]}]} {
  164.             error "Problem with launching file (out of memory?)"
  165.         }
  166.     }        
  167.     
  168.     # Return the name of the chosen application
  169.     return [file tail [set $path]]
  170. }
  171.  
  172.  
  173. #===============================================================================
  174.  
  175. # Switch to 'sig', launching if necesary
  176. proc launchForeAppl {sig} {
  177.     if {[catch {nameFromAppl $sig} name]} {
  178.         alertnote "Can't find app w/ sig '$sig'. Try rebuilding your desktop or changing your helper apps."
  179.         error ""
  180.     }
  181.     if {![file exists $name]} {
  182.         alertnote "Sig '$sig' is mapped to '$name', which doesn't exist. Try changing your helper apps."
  183.         error ""
  184.     }
  185.     if {[catch {switchTo "'$sig'"}]} {
  186.         launch -f $name
  187.     }        
  188.     return $name
  189. }
  190.  
  191. # Ensure that the app is at least running in the background.
  192. proc launchBackAppl {sig} {
  193.     if {[catch {nameFromAppl $sig} name]} {
  194.         alertnote "Can't find app w/ sig '$sig'. Try rebuilding your desktop or changing your helper apps."
  195.         error ""
  196.     }
  197.     if {![file exists $name]} {
  198.         alertnote "Sig '$sig' is mapped to '$name', which doesn't exist. Try changing your helper apps."
  199.         error ""
  200.     }
  201.     launch $name
  202.     return $name
  203. }
  204.  
  205. # Check to see if any of the 'sigs' is running. If so, return its name.
  206. # Otherwise, attempt to launch the file named by 'sig'.
  207. proc launchBackApplSigs    {sigs sig {prompt "Please locate the application:"}} {
  208.     global $sig    modifiedVars
  209.     foreach    p [processes] {
  210.         if { [set ind [lsearch -exact $sigs [lindex $p 1]]] >= 0 } {
  211.             set s [lindex $sigs $ind]
  212.             if { ![info exists $sig] || ($s != [set    $sig]) } {
  213.                 set    $sig $s
  214.                 lappend    modifiedVars $sig
  215.             }
  216.             return [nameFromAppl $s]
  217.         }
  218.     }
  219.     if {![info exists $sig] || ([set $sig] == "")}    {
  220.         set    $sig [getFileSig [getfile $prompt]]
  221.         lappend    modifiedVars $sig
  222.     }
  223.     return [launchBackAppl [set    $sig]]
  224. }
  225.  
  226. proc getApplSig {prompt sig} {
  227.     global $sig modifiedVars
  228.     if {[catch {nameFromAppl [set $sig]}]} {
  229.         set $sig [getFileSig [getfile $prompt]]
  230.         lappend modifiedVars $sig
  231.     }
  232. }
  233.  
  234. #================================================================================
  235. # Excalibur is the only Mac spell-checker that I know of which will handle LaTeX as
  236. # well as ordinary text.
  237.  
  238.  
  239. proc spellcheckWindow {} {
  240.     global resumeRevert
  241.  
  242.     set name [launchForeAppl XCLB]
  243.  
  244.     if {[winDirty]} {
  245.         if {[askyesno "Save '[lindex [winNames] 0]'?"] == "yes"} {
  246.             save
  247.         }
  248.     }
  249.     sendOpenEvent noReply [file tail $name] [car [winNames -f]]
  250.     set resumeRevert 1
  251. }
  252.  
  253. proc spellcheckSelection {} {
  254.     global excaliburPath 
  255.  
  256.     catch {checkRunning Excalibur XCLB excaliburPath} name
  257.  
  258.     if {[getPos] == [selEnd]} {
  259.         beep
  260.         message "No selection"
  261.         return;
  262.     }
  263.     copy
  264.     switchTo $name
  265. }
  266.  
  267. #================================================================================
  268.  
  269.  
  270. proc alphaHelp {} {
  271.     global HOME alphaLite
  272.     if $alphaLite {
  273.         edit -r "$HOME:Help:Quick Start"
  274.     } else {
  275.         edit -r "$HOME:Help:Manual"
  276.     }
  277. }
  278.  
  279.  
  280. proc tclHelp {} {
  281.     global HOME
  282.     edit -r "$HOME:Help:Tcl Commands"
  283. }
  284.  
  285.  
  286. proc dividingLine {} {
  287.     insertText "===============================================================================\r"
  288. }
  289. bind 'l' <C> dividingLine
  290.  
  291. proc texDividingLine {} {
  292.     insertText "%===============================================================================\r"
  293. }
  294. bind 'l' <C> texDividingLine TeX
  295.  
  296. proc cDividingLine {} {
  297.     insertText "//===============================================================================\r"
  298. }
  299. bind 'l' <C> cDividingLine C
  300. bind 'l' <C> cDividingLine C++
  301.  
  302. proc tclDividingLine {} {
  303.     insertText "#===============================================================================\r"
  304. }
  305. bind 'l' <C> tclDividingLine Tcl
  306.  
  307.  
  308. #================================================================================
  309.  
  310. if {![string length [info commands oldCd]]} {
  311.     rename cd oldCd
  312. }
  313.  
  314. proc cd args {
  315.     global HOME
  316.     if {[llength $args]} {
  317.         set path [string trim [eval list $args] "        \{\}"]
  318.         if {![regexp {:} $path]} {
  319.             set path ":$path"
  320.         }
  321.         oldCd $path
  322.     } else {
  323.         oldCd $HOME
  324.     }
  325. }
  326.  
  327.  
  328.  
  329. #############################################################################
  330. #  List the name and value of each element of the array $arrName.
  331. #  (Convenient to use as a shell command.)
  332. #
  333. #  Note: it's slower to insert the lines one-by-one like this, but 
  334. #  assembling everything in $lines before inserting can seriously crash Alpha
  335. #  if the result is too big.  (Trying to list the contents of $auto_index()
  336. #  will do it.)  This method seems to be more robust.
  337. #
  338. proc listArray {arrName} {
  339.     global $arrName
  340.     set lines {}
  341.     if {![catch {info vars $arrName}]} {
  342.         foreach nm [lsort -ignore [array names $arrName]] {
  343.             append lines [format "\r%-20s \"%s\"" $nm [set ${arrName}($nm)]]
  344.         }
  345.         insertText $lines
  346.     } else {
  347.         alertnote "\"$arrName\" doesn't exist in this context"
  348.     }
  349. }
  350.  
  351.  
  352.  
  353. #================================================================================
  354.     
  355. proc selectParagraph {} {
  356.     set pos [getPos]
  357.     set start [paraStart $pos] 
  358.     set finish [paraFinish $pos]
  359.     goto $start
  360.     select $start $finish
  361. }
  362.  
  363. # wrapText ==  getText ; breakIntoLines ; replaceText
  364. # Remove text from window, transform (join, del-ws), insert back into window.
  365. proc fillTextByPar {from to} {
  366.     set text [getText $from $to]
  367.     regsub -all "\r(\[ \t\]*\r)+" $text "\r\r\r" text
  368.     regsub -all "(\[^\r\])\r" $text "\\1 " text
  369.     regsub -all "\[ \t\]+" $text " " text
  370.     return [breakIntoLines $text]
  371. }
  372.  
  373. proc fillRegionByPar {{start -1} {finish -1}} {
  374. #    # if {[getPos] == [selEnd]} { return}
  375.     if {($start < 0) || ($finish < 0)} {
  376.         set start [lineStart [getPos]]
  377.         set finish [selEnd] }
  378.     if {$start >= $finish} return
  379.     goto $start
  380.     set text [fillTextByPar $start $finish]
  381.     replaceText $start $finish $text "\r"
  382. }
  383.     
  384. #
  385. # join Lines in region -- if no optional args, use selection
  386. #
  387. proc joinRegion {{from -1} {to -1}} {
  388.     if {($from < 0) || ($to < 0)} {    set from [getPos] ; set to [selEnd] }
  389.     if {$from >= $to} return
  390.     set text [getText $from $to]
  391.     regsub -all "\r(\[ \t\]*\r)+" $text "\r\r\r" text
  392.     regsub -all "(\[^\r\])\r" $text "\\1 " text
  393.     replaceText $from $to $text "\r"
  394. }
  395. # WARNING:    regsub ^$ refers to string endpts (not lines)
  396. # FUTURE:    filterLines like perl:
  397. #    replaceText[apply_to_all(cmd,split [getText [getPos] [selEnd]] "\r")]
  398. # OR:    replaceInRegion: dup_\r, $=>\r ??
  399. #
  400.  
  401.  
  402. #
  403. # Remove text from window, transform (delete dup ws), insert back into window.
  404. #
  405. # inputs: message, alertnote, askyesno, listpick, prompt KILLS SELECTION.
  406. # search: bnds = search -forward -regExpr -ignoreCase -matchWords -noabort 
  407. #        -l limit pat pos
  408. proc regsubInRegion {from to srch repl} {
  409.     if {![string length $srch]} return
  410.     if {$from >= $to} return
  411.     set text [getText $from $to]
  412.     regsub -all "$srch" $text "$repl" text
  413.     replaceText $from $to $text
  414. }
  415. #    while {($pos < $to) &&
  416. #          ![catch {search -s -f 1 -r 1 -i 1 -m 0 "$srch" $pos} mtch]} {
  417. #        set mbeg [lindex $mtch 0]
  418. #        set pos [lindex $mtch 1]
  419. #        replaceText $mbeg $pos $repl }
  420.  
  421. #proc backSlashSub {arg} { eval [concat return "\"$arg\""] }
  422.  
  423. proc backSlashSub {arg} {
  424.     regsub -all {\\} $arg {\\\\} arg
  425.     regsub -all {\[} $arg {\\[} arg
  426.     regsub -all {\]} $arg {\\]} arg
  427.     eval [concat return "\"$arg\""]
  428. }
  429.  
  430. proc replaceInRegion {} {
  431.     if [catch {prompt "Search RegExpr:" ""} srch] return
  432.     if [catch {prompt "Replace String:" ""} repl] return
  433.     if {![string length $srch]} return
  434.     regsubInRegion [getPos] [selEnd] \
  435.         [backSlashSub "$srch"] [backSlashSub "$repl"]
  436. }
  437.  
  438. #
  439. # Apply command to each line (or paragraph) in selection ;
  440. #    if no cmd arg then prompts for it
  441. #
  442. proc filterLines {{cmd 0} {parunit 0}} {
  443.     if {$cmd == 0} {
  444.       if {[catch { prompt "Line-filter command: " "" } cmd]} { return } }
  445.     if {![string length $cmd]} return
  446.     set unitStart lineStart
  447.     set unitEnd nextLineStart
  448.     if {$parunit} {
  449.         set unitStart paraStart
  450.         set unitEnd paraFinish }
  451.     set pos [$unitStart [getPos]]
  452.     set finish [selEnd]
  453.     if {$pos >= $finish} return
  454.     goto $pos
  455.     createTMark "filterLend" $finish
  456.     set next [$unitEnd $pos]
  457.     while {(($next > $pos) && ($pos < $finish))} {
  458.         goto [expr $next-1]
  459.         createTMark "filterLnext" $next
  460.         setMark
  461.         goto $pos
  462.         markHilite
  463.         if {[catch [list uplevel #0 "$cmd"] retval]} {
  464.             select $pos $finish
  465.             alertnote $retval
  466.             return
  467.         }
  468.         if {$next==$finish} break
  469.         set ind [lsearch -regexp [lindex [getTMarks] 0] "filterLend.*"]
  470.         set finish [lindex [lindex [lindex [getTMarks] 0] $ind] 2]
  471.         gotoTMark "filterLnext"
  472.         set pos [$unitStart [getPos]]
  473.         set next [$unitEnd $pos]
  474.     }
  475.     removeTMark "filterLend"
  476.     removeTMark "filterLnext"
  477. }
  478.  
  479.  
  480. proc filterParagraphs {{cmd 0}} { filterLines $cmd 1 }
  481.  
  482. # WARNING: deselecting sets the mark to selEnd
  483. proc sortParagraphs {{from -1} {to -1}} {
  484.     if {($from < 0) || ($to < 0)} {    set from [getPos] ; set to [selEnd] }
  485.     if {$from >= $to} return
  486.     joinRegion {$from $to}
  487.     select [getPos] [nextLineStart [getMark]]
  488.     sortLines
  489.     select [getPos] [getPos]
  490.     regsubInRegion [getPos] [getMark] "\r" "\r\r" 
  491.     wrapRegion
  492. }
  493.  
  494. #
  495. # Sample
  496. #
  497. proc filterRegion {{from -1} {to -1} {cmd 0} {newwin 0}} {
  498.     if {$cmd == 0} {
  499.       if {[catch { prompt "Eval command: " "" } cmd]} { return }
  500.     }
  501.     if {![string length $cmd]} return
  502.     if {($from < 0) || ($to < 0)} {    set from [getPos] ; set to [selEnd] }
  503.     if {$from >= $to} return
  504.     set pos [getPos]
  505.     set text [getText $from $to]
  506.     set text [$cmd $text]
  507.     replaceText $from $to $text "\r"
  508.     goto $pos
  509. }
  510.  
  511.  
  512. #
  513. set lastEvaled ""
  514. proc evaluate {} {
  515.     global lastEvaled
  516.     if {[string length $lastEvaled]} {
  517.         set p "M-x ($lastEvaled): "
  518.     } else {
  519.         set p "M-x: "
  520.     }
  521.     if {[catch {statusPrompt $p} text]} {return}
  522.     if {![string length $text]} {set text $lastEvaled}
  523.     $text
  524.     set lastEvaled $text
  525. }
  526.  
  527.  
  528. # First, define macros to bypass the electric braces.
  529. proc ordLeftBrace {} {
  530.     insertText "        \{"
  531. }
  532. bind {'['} <cs> ordLeftBrace
  533.  
  534. proc ordRightBrace {} {
  535.     insertText "\}"
  536.     blink [matchIt "\}" [expr [getPos]-1]]
  537. }
  538. bind {']'} <cs> ordRightBrace
  539.     
  540. proc quoteWord {} {
  541.     backwardWord
  542.     insertText "'"
  543.     forwardWord
  544.     insertText "'"
  545. }
  546. bind ''' <z> quoteWord
  547.  
  548. #================================================================================
  549.  
  550. proc tomac {fname} {
  551.     set fd [open $fname "r"]
  552.     set text [read $fd]
  553.     close $fd
  554.     set fd [open $fname "w"]
  555.     regsub "\n" $text "\r" text
  556.     puts -nonewline $fd $text
  557.     close $fd
  558. }
  559.  
  560. proc tounix {fname} {
  561.     set fd [open $fname "r"]
  562.     set text [read $fd]
  563.     close $fd
  564.     set fd [open $fname "w"]
  565.     regsub "\r" $text "\n" text
  566.     puts -nonewline $fd $text
  567.     close $fd
  568. }
  569.  
  570.  
  571. proc cat args {
  572.     set files ""
  573.     foreach a $args {
  574.         foreach f [glob $a] {
  575.             lappend files $f
  576.         }
  577.     }
  578.     foreach f $files {
  579.         append text "==============<$f>==============\r"
  580.         set fd [open $f "r"]
  581.         append text "[read $fd]\r\r"
  582.         close $fd
  583.     }
  584.     return $text
  585. }
  586.  
  587. proc catto args {
  588.     set len [llength $args]
  589.     set to [lindex $args [expr $len -1]]
  590.     set args [lrange $args 0 [expr $len -2]]
  591.  
  592.     set files ""
  593.     foreach a $args {
  594.         foreach f [glob $a] {
  595.             lappend files $f
  596.         }
  597.     }
  598.     foreach f $files {
  599.         append text "==============<$f>==============\r"
  600.         set fd [open $f "r"]
  601.         append text "[read $fd]\r\r"
  602.         close $fd
  603.     }
  604.  
  605.     set dfile $to
  606.     if {[file exists $dfile]} {
  607.         set fid [open $dfile "a"]
  608.     } else {
  609.         set fid [open $dfile "w"]
  610.     }
  611.     puts $fid $text
  612.     close $fid
  613. }
  614.  
  615.  
  616. ##############################################################################
  617. #  To be used in the windows created by "matchingLines" or by batch searches.
  618. #
  619. #  With the cursor positioned in a line corrsponding to a match, 
  620. #  go back and select the line in the original file that 
  621. #  generated this match.  (Like emacs 'Occur' functionality)
  622. #
  623. proc gotoMatch {} {
  624.     if {[string match "*MAILBOX*" [lindex [winNames] 0]]} {
  625.         mailGotoMatch
  626.         return
  627.     }
  628.     global tileHeight tileWidth tileTop tileLeft tileHeight errorHeight errorDisp tileMargin
  629.     set errorDisp [expr (2 * ($tileHeight - $tileMargin)) / 3]
  630.     set text [getText [lineStart [getPos]] [expr [nextLineStart [getPos]] - 1]]
  631.     set ind1 [string first "∞" $text]
  632.     set ind2 [string last "∞" $text]
  633.     if {$ind1 == $ind2} {
  634.         set fname [string trim [string range $text $ind1 end] {∞}]
  635.         set msg ""
  636.     } else {
  637.         set fname [string trim [string range $text $ind1 $ind2] {∞}]
  638.         set msg [string trim [string range $text $ind2 end] {∞}]
  639.     }
  640.     
  641.     set top $tileTop
  642.     set geo [getGeometry]
  643.     if {([lindex $geo 0] != $tileLeft) || ([lindex $geo 1] != $top) || ([lindex $geo 3] != $errorHeight) } {
  644.         moveWin $tileLeft $top
  645.         sizeWin $tileWidth $errorHeight
  646.     }
  647.     set mar $tileMargin
  648.     incr top [expr $errorHeight + $mar]
  649.     if {[expr {[lsearch [winNames -f] "*$fname"] >= 0}]} {
  650.         if {[string match ":*" $fname]} {
  651.             set fname [file tail $fname]
  652.         }
  653.         bringToFront $fname
  654.         set geo [getGeometry]
  655.         if {([lindex $geo 0] != $tileLeft) || ([lindex $geo 1] != $top) || ([lindex $geo 2] != $tileWidth) || ([lindex $geo 3] != $errorDisp) } {
  656.             sizeWin $tileWidth $errorDisp
  657.             moveWin $tileLeft $top
  658.         }
  659.     } elseif {[file exists $fname]} {
  660.         edit -g $tileLeft $top $tileWidth $errorDisp $fname
  661.     } else {
  662.         if {![string match "*Link*" [getText 0 [nextLineStart 0]]]} {
  663.             alertnote "File \" $fname \" not found." 
  664.         }
  665.         return
  666.     }
  667.     if {[regexp {Line ([0-9]+):} $text dummy line]} {
  668.         set pos [rowColToPos $line 0]
  669.         select $pos [nextLineStart $pos]
  670.     }
  671.     message $msg
  672. }
  673. bind 'c' <Cz>        gotoMatch
  674.  
  675.  
  676. #================================================================================
  677.  
  678. proc prevIntro {} {
  679.     set res [search -s -f 0 -r 0 {== } [getPos]]
  680.     display [lineStart [expr [lineStart [lindex $res 0]] - 1]]
  681. }
  682.  
  683. proc nextIntro {} {
  684.     set res [search -s -f 1 -r 0 {== } [getPos]]
  685.     set res [lindex $res 1]
  686.     set res [search -s -f 1 -r 0 {== } $res]
  687.     display [lineStart [expr [lineStart [lindex $res 0]] - 1]]
  688. }
  689.  
  690. #================================================================================
  691.  
  692. proc searchStart {} {
  693.     global search_start
  694.     select [getPos]
  695.     setMark
  696.     if {[catch {goto $search_start}]} {message "No previous search"}
  697. }
  698.  
  699. #================================================================================
  700.  
  701.  
  702. proc listBindings {} {
  703.     new -n {* Key Bindings *}
  704.     insertText [bindingList]
  705.  
  706.     goto 0
  707.     setWinInfo dirty 0
  708.     setWinInfo read-only 1
  709. }
  710.  
  711.  
  712. proc listFunctions {} {
  713.     global winModes
  714.     new -n {* Functions *}
  715.     insertText "===\r\tCommand-double-click on a function to see its definition\r===\r\r" [join [lsort -ignore [info commands]] "\r"] "\r"
  716.     goto 0
  717.     setWinInfo dirty 0
  718.     changeMode [set winModes([lindex [winNames] 0]) Tcl]
  719. }
  720.  
  721.  
  722. #================================================================================
  723.  
  724. proc printArray {arr} {
  725.     global $arr
  726.         foreach n [array names $arr] {
  727.         append text "$n '[set ${arr}($n)]'\r"
  728.     }
  729.     return [string trim $text "\r"]
  730. }
  731.  
  732. #================================================================================
  733.  
  734. #================================================================================
  735.  
  736. proc sPrompt {msg def} {
  737.     global useStatusBar
  738.     if {!$useStatusBar} {return [prompt $msg $def]}
  739.     if {[catch {statusPrompt "$msg ($def): "} ans]} {
  740.         error "cancel"
  741.     }
  742.     if {![string length $ans]} {return $def}
  743.     return $ans
  744. }
  745.  
  746.  
  747. proc choicesProc {curr c} {
  748.     global choiceList
  749.     if {$c != "\t"} {return $c}
  750.     
  751.     set matches {}
  752.     foreach w $choiceList {
  753.         if {[string match "$curr*" $w]} {
  754.             lappend matches $w
  755.         }
  756.     }
  757.     if {![llength $matches]} {
  758.         beep
  759.     } else {
  760.         return [string range [largestPrefix $matches] [string length $curr] end]
  761.     }
  762.     return ""
  763. }
  764.  
  765.  
  766. proc sPromptChoices {msg def choiceListIn} {
  767.     global useStatusBar choiceList
  768.     set choiceList $choiceListIn
  769.     if {[catch {statusPrompt -f "$msg ($def): " choicesProc} ans]} {
  770.         error "cancel"
  771.     }
  772.     if {![string length $ans]} {return $def}
  773.     return $ans
  774. }
  775.  
  776. #================================================================================
  777. proc quoteChar {} {
  778.     message "Literal keystroke to be inserted:"
  779.     insertText [getChar]
  780. }
  781. #===============================================================================
  782.  
  783. proc saveACopyAs {} {
  784.     if {[file exists [set nm [car [winNames -f]]]]} {
  785.         set nm2 [putfile "Save a copy as:" [file tail $nm]]
  786.         cp $nm $nm2
  787.     }
  788. }
  789. #===============================================================================
  790. proc removeDups {l} {
  791.     set lout ""
  792.     foreach f $l {
  793.         if {![info exists silly($f)]} {
  794.             set silly($f) 1
  795.             lappend lout $f
  796.         }
  797.     }
  798.     return $lout
  799. }
  800.             
  801.  
  802. #===============================================================================
  803.  
  804. proc printLeftHeader {pg} {
  805.     global printHeader printHeaderTime printHeaderFullPath
  806.     
  807.     if {!$printHeader} return ""
  808.     
  809.     if {$printHeaderFullPath} {
  810.         set text [car [winNames -f]]
  811.     } else {
  812.         set text [lindex [winNames] 0]
  813.     }
  814.     
  815.     if {$printHeaderTime} {
  816.         append text "      [join [mtime [now] short]]"
  817.     }
  818. }
  819.  
  820. proc printRightHeader {pg} {
  821.     return "Page $pg"
  822. }
  823.  
  824. #===============================================================================
  825.  
  826. proc toggleNumLock {} {
  827.     global numLock modifiedVars
  828.     
  829.     set numLock [expr -1 * ($numLock - 1)]
  830.     lappend modifiedVars numLock
  831. }
  832.  
  833. #===============================================================================
  834.  
  835. proc register {} {
  836.     global HOME
  837. #    edit -r "$HOME:Help:Registering"
  838.     launch -f "$HOME:Register"
  839. }
  840.  
  841. #===============================================================================
  842. # Useful for -command flag of 'lsort'.
  843. proc sortByTail {one two} {
  844.     string compare [file tail $one] [file tail $two]
  845. }
  846.  
  847.  
  848. #===============================================================================
  849.  
  850. proc cmdDoubleClick {{from -1} {to -1} {shift 0} {option 0} {control 0}} {
  851.     global mode alphaLite
  852.     
  853.     if {!$alphaLite && [string length [set whe [expandURL]]]} {
  854.         sendUrl [getSelect]
  855.     } else {
  856.         if {$from < 0} {
  857.             set from [getPos]
  858.             set to [selEnd]
  859.             if {$from == $to} {
  860.                 hiliteWord
  861.                 set from [getPos]
  862.                 set to [selEnd]
  863.             }
  864.         }
  865.         
  866.         if {[string length [info commands ${mode}DblClick]]} {
  867.             if {[llength [info args ${mode}DblClick]] == 2} {
  868.                 ${mode}DblClick $from $to
  869.             } else {
  870.                 ${mode}DblClick $from $to $shift $option $control
  871.             }
  872.         } else {
  873.             message "No docs"
  874.         }
  875.     }    
  876. }
  877.  
  878. #===============================================================================
  879.  
  880.  
  881. proc editMark {fname mname args} {
  882.     if {[set pos [lsearch [winNames -f] "*$fname*"]] >= 0}  {
  883.         bringToFront [lindex [winNames -f] $pos]
  884.     } else {
  885.         if {[lsearch $args {-r}] >= 0} {
  886.             edit -r "$fname"
  887.         } else {
  888.             edit "$fname"
  889.         }
  890.     }
  891.     if {[lsearch [getNamedMarks -n] "* ${mname}*"] < 0} {
  892.         global    mode
  893.         catch {${mode}MarkFile}
  894.     } 
  895.     gotoMark $mname
  896. }
  897.  
  898.  
  899. proc winDirty {} {
  900.     getWinInfo arr
  901.     return $arr(dirty)
  902. }
  903.  
  904.  
  905. #===============================================================================
  906.  
  907. proc lreverse {l} {
  908.     if {[llength $l] > 1} {
  909.         set first [lindex $l 0]
  910.         set l [lreverse [lrange $l 1 end]]
  911.         lappend l $first
  912.     }
  913.     return $l
  914. }
  915.  
  916.     
  917. #===============================================================================
  918.  
  919.  
  920. set {patternLibrary(Pascal to C Comments)}      { {\{([^\}]*)\}}    {/* \1 */}     }
  921. set {patternLibrary(C++ to C Comments)}            { {//(.*)}            {/* \1 */}     }
  922. set {patternLibrary(Space Runs to Tabs)}        { { +}                {\t}         }
  923.  
  924.  
  925.  
  926. proc getPatternLibrary {} {
  927.     global patternLibrary
  928.     
  929.     foreach nm [array names patternLibrary] {
  930.         lappend nms [concat [list $nm] $patternLibrary($nm)]
  931.     }
  932.     return $nms
  933. }
  934.  
  935. proc rememberPatternHook {search replace} {
  936.     global patternLibrary
  937.     if {[catch {set name [prompt "New pattern's name?" ""]}]} {
  938.         return ""
  939.     }
  940.     addArrDef patternLibrary $name [list $search $replace]
  941.     set patternLibrary($name) [list $search $replace]
  942.     return $name
  943. }
  944.  
  945. proc deletePatternHook {} {
  946.     global patternLibrary
  947.     
  948.     
  949.     set temp [list prompt "Delete which pattern?" [lindex [array names patternLibrary] 0] "Pats:"]
  950.     set name [eval [concat $temp [array names patternLibrary]]]
  951.     removeArrDef patternLibrary $name
  952.     unset patternLibrary($name)
  953. }
  954.  
  955. #===============================================================================
  956. # Support for Peter Gontier's 'ClickWarrior' (Doesn't work for 68k).
  957. #===============================================================================
  958.  
  959. eventHandler ALFA CWOF clickHandler
  960.  
  961. proc clickHandler {msg} {
  962.     global HOME ALPHA CODEWarrior CWCLASS
  963.     switchTo $ALPHA
  964.     checkCw
  965.     if {[regexp {“(.*)”.*«.*».*«(.*)».*«(.*)»} $msg dummy fname find sind]} {
  966.         set res [AEBuild -t 500000 -r $CODEWarrior $CWCLASS GFil "----" "long(«0000$find»)" Segm "long($sind)"]
  967.         if {[regexp {FTxt} $res]} {
  968.             regexp {«(.*)»} $res dummy spec
  969.             set f [specToPathName $spec]
  970.             edit $f
  971.         }
  972.     }
  973. }
  974.  
  975. #===============================================================================
  976. proc quickFind {} {isearch}
  977. proc reverseQuickFind {} {rsearch}
  978.  
  979. proc pushPosition {} {pushMark}
  980. proc popPosition {} {popMark}
  981. #===============================================================================
  982. proc literalChar {} {
  983.     return [expr {[lookAt [expr [getPos] - 1]] == "\\"}]
  984. }
  985. proc isSelection {} {
  986.     return [string length [getSelect]]
  987. }
  988.  
  989. proc findPatJustBefore { findpat pat {pos ""} {matchw ""} } {
  990.     if { $pos == "" } {set pos [getPos] }
  991.     if { $matchw != "" } { upvar  $matchw word }
  992.     if { ![catch {search -s -f 0 -r 1 "$findpat" $pos} res] } {
  993.         if { [regexp "$pat" [getText [lindex $res 0] $pos] dum word] } {
  994.             return [lindex $res 0]
  995.         }
  996.     }
  997.     return
  998. }
  999.  
  1000. #===============================================================================
  1001. proc mkdir {dir} {
  1002.     oldMkdir [list $dir]
  1003. }
  1004.  
  1005. proc rmdir {dir} {
  1006.     oldRmdir [list $dir]
  1007. }
  1008.  
  1009. #===============================================================================
  1010. proc textToAlpha {{dir ""}} {
  1011.     set num 0
  1012.     if {![string length $dir]} {
  1013.         set dir [get_directory -p "Creators to 'ALFA':"]
  1014.     }
  1015.  
  1016.     if {![catch {glob "$dir:*"} files]} {
  1017.         foreach f $files {
  1018.             if {[file isfile $f] && ([getFileType $f] == "TEXT") && ([getFileSig $f] != "ALFA")} {
  1019.                 message $f
  1020.                 setFileInfo $f creator ALFA
  1021.                 incr num
  1022.             } elseif {[file isdir $f]} {
  1023.                 incr num [textToAlpha $f]
  1024.             }
  1025.         }
  1026.     }
  1027.     message "Converted $num files"
  1028.     return $num
  1029. }
  1030.  
  1031.  
  1032. #===============================================================================
  1033.  
  1034. proc briefThing {} {
  1035.     global lastBrief
  1036.     getWinInfo arr
  1037.     set curr $arr(currline)
  1038.     set where [posToRowCol [getPos]]
  1039.     set row [car $where]
  1040.     set col [cadr $where]
  1041.     
  1042.     if {$col} {
  1043.         set lastBrief [getPos]
  1044.         goto [lineStart [getPos]]
  1045.     } elseif {$curr != $row} {
  1046.         goto [rowColToPos $curr 0]
  1047.     } elseif {[getPos]} {
  1048.         goto 0
  1049.     } else {
  1050.         goto $lastBrief
  1051.     }
  1052. }
  1053.  
  1054. ########################################
  1055. #                                       #
  1056. #    A few random lisp'ish functions.   #
  1057. #                                       #
  1058. ########################################
  1059.  
  1060. proc car {l} {lindex $l 0}
  1061. proc cadr {l} {lindex $l 1}
  1062. proc caddr {l} {lindex $l 2}
  1063. proc cadddr {l} {lindex $l 3}
  1064. proc caddddr {l} {lindex $l 4}
  1065. proc cdr {l} {lrange $l 1 end}
  1066. proc cddr {l} {lrange $l 2 end}
  1067. proc cons {e l} {concat [list $e] $l}
  1068. proc mapcar args {return [eval map $args]}
  1069.  
  1070. proc map {func l} {
  1071.     set out {}
  1072.     foreach el $l {
  1073.         lappend out [eval $func [list $el]]
  1074.     }
  1075.     return $out
  1076. }
  1077.  
  1078.  
  1079. #===============================================================================
  1080.  
  1081. proc deconstruct {} {
  1082.     global HOME 
  1083.     
  1084.     set files {}
  1085.     if {![catch {glob "$HOME:Tcl:Modes:*Mode.tcl"} modes]} {
  1086.         set files $modes
  1087.     }
  1088.     if {![catch {glob "$HOME:Tcl:Menus:*Menu.tcl"} menus]} {
  1089.         set files [concat $files $menus]
  1090.     }
  1091.     
  1092.     foreach f $files {
  1093.         regexp {.*:(.*)M.*.tcl} $f dummy it
  1094.         set theFiles($it) $f
  1095.         lappend tails $it
  1096.     }
  1097.  
  1098.     set res [listpick -p "Permanently remove which modes and menus?" -l [lsort -ignore $tails]]
  1099.     
  1100.     if {[llength $res] && ([askyesno "Are you absolutely sure?"] == "yes")} {
  1101.         foreach tag $res {
  1102.             set name $theFiles($tag)
  1103.             regexp {(.*)M.*.tcl} $name dummy prefix
  1104.             foreach f [glob "${prefix}*.tcl"] {
  1105.                 lappend rfiles $f
  1106.             }
  1107.  
  1108.             set tag [file tail $tag]
  1109.             if {$tag == "perl"} {
  1110.                 catch {rm $HOME:Help:*Perl*}
  1111.             } elseif {$tag == "latex"} {
  1112.                 catch {rm $HOME:Help:LaTeX*}
  1113.             } elseif {$tag == "bibtex"} {
  1114.                 catch {rm $HOME:Help:Bib*}
  1115.             } elseif {$tag == "html"} {
  1116.                 catch {rm $HOME:Help:HTML*}
  1117.             }
  1118.         }
  1119.  
  1120.         foreach f $rfiles {
  1121.             catch {rm $f}
  1122.         }
  1123.  
  1124.         foreach dir [list "$HOME:Tools" "$HOME:Tcl:ElectricAlias" "$HOME:Tcl:UserCode" "$HOME:Help"] {
  1125.             if {[file exists $dir] && ([askyesno "Remove '$dir'?"] == "yes")} {
  1126.                 if {[catch {recursiveRm $dir}]} {
  1127.                     alertnote "Problem removing '$dir'."
  1128.                 }
  1129.             }
  1130.         }
  1131.         
  1132.         rebuildTclIndices
  1133.  
  1134.         alertnote "You must now restart Alpha..."
  1135.         quit
  1136.     }
  1137. }
  1138.  
  1139. proc recursiveRm dir {
  1140.     if {![catch {glob $dir:*} files]} {
  1141.         foreach f $files {
  1142.             if {[file isdir $f]} {
  1143.                 recursiveRm $f
  1144.             } else {
  1145.                 rm $f
  1146.             }
  1147.         }
  1148.     }
  1149.     rmdir $dir
  1150. }
  1151.  
  1152. ###########################################################################
  1153. #  better-cp-mv.tcl  -- modification of your routines, by Mark Nagata
  1154. #  for Alpha 5.72,  1/04/94
  1155. ###########################################################################
  1156. proc cp args {
  1157.     if {[set len [llength $args]] < 2} {
  1158.         error "usage: cp <file1> <file2>\r       cp <file1> .... <dir>"
  1159.     }
  1160.     set len [expr $len-1]
  1161.     set dir [lindex $args $len]
  1162.     if {![regexp {:} $dir] && $dir != ""} {
  1163.         set dir ":$dir"
  1164.     }
  1165.     if {[regexp {:$} $dir]} {
  1166.         set dir [string trimright $dir {:}]
  1167.     }
  1168.     set args [lreplace $args $len $len]
  1169.     set files {}
  1170.     foreach arg $args {
  1171.         append files " " [glob $arg]
  1172.     }
  1173.     set report ""
  1174.     if {[llength $files] == 1} {
  1175.         set f [lindex $files 0]
  1176.         if {[file exists $dir]} {
  1177.             set targ $dir:[file tail $f]
  1178.             append report $f\ ->\ $targ \r 
  1179.             copyFile $f $targ
  1180.         } else {
  1181.             append report $f\ ->\ $dir \r
  1182.             copyFile $f $dir
  1183.         }
  1184.     } else {
  1185.         foreach f $files {
  1186.             message [file tail $f]
  1187.             set targ $dir:[file tail $f]
  1188.             if {[catch {copyFile $f $targ} that]} {
  1189.                 append report "Error copying '$f': $that\r"
  1190.             } else {
  1191.                 append report $f\ ->\ $targ \r
  1192.             }
  1193.         }
  1194.     }
  1195.     echo [string trimright $report]
  1196. }
  1197.  
  1198. proc mv args {
  1199.     if {[set len [llength $args]] < 2} {
  1200.         error "usage: mv <file1> <file2>\r       mv <file1> .... <dir>"
  1201.     }
  1202.     set len [expr $len-1]
  1203.     if {![regexp {.*[^:]} [lindex $args $len] dir]} {
  1204.         set dir [string range [lindex $args $len] 1 end]
  1205.     }
  1206.     if {![regexp {:} $dir] && $dir != ""} {
  1207.         set dir [concat :$dir]}
  1208.     set args [lreplace $args $len $len]
  1209.     set files {}
  1210.     foreach arg $args {
  1211.         append files " " [glob $arg]
  1212.     }
  1213.     set report ""
  1214.     if {[llength $files] == 1} {
  1215.         set f [lindex $files 0]
  1216.         if {[file exists $dir]} {
  1217.             set targ $dir:[file tail $f]
  1218.             append report $f\ >->\ $targ \r
  1219.             moveFile $f $targ
  1220.         } else {
  1221.             append report $f\ >->\ $dir \r
  1222.             moveFile $f $dir
  1223.         }
  1224.     } else {
  1225.         foreach f $files {
  1226.             message [file tail $f]
  1227.             set targ $dir:[file tail $f]
  1228.             if {[catch {moveFile $f $targ} that]} {
  1229.                 append report "Error moving '$f': $that\r"
  1230.             } else {
  1231.                 append report $f\ >->\ $targ \r
  1232.             }
  1233.         }
  1234.     }
  1235.     echo [string trimright $report]
  1236. }
  1237.  
  1238.  
  1239. proc rm args {
  1240.     set files {}
  1241.     foreach arg $args {
  1242.         append files " " [glob $arg]
  1243.     }
  1244.     foreach f $files {
  1245.         message [file tail $f]
  1246.         removeFile $f
  1247.     }
  1248. }
  1249.  
  1250.  
  1251. #===============================================================================
  1252. proc deleteTill {} {
  1253.     set pos [getPos]
  1254.     set pat [statusPrompt "Delete text until?: (Date): "]
  1255.     if {$pat == ""} {set pat Date}
  1256. #     set pat [prompt "Delete text until?" "Date"]
  1257.     if {![catch {search -s -f 1 -r 1 -i 0 -m 0 -- $pat $pos} data]} {
  1258.         deleteText $pos [lindex $data 0]
  1259.         return
  1260.     }
  1261.     beep
  1262.     message "no match."
  1263. }
  1264. ascii  0x8   <c>  deleteTill 
  1265. #===============================================================================
  1266.  
  1267. proc helperApps {} {
  1268.     set sigs [info globals *Sig]
  1269.     regsub -all {Sig} $sigs {} sigs
  1270.     set sig [listpick -p "Change/inspect which helper?" [lsort $sigs]]
  1271.     set sig ${sig}Sig
  1272.     global $sig modifiedVars
  1273.     if {![info exists $sig] || ([set $sig] == "")} {
  1274.         set text "Currently unassigned.   Set?"
  1275.     } elseif {[catch {nameFromAppl '[set $sig]'} name]} {
  1276.         set text "App w/ sig '[set $sig]' doesn't seem to exist.   Change?"
  1277.     } else {
  1278.         set text "Current value is '$name'.   Change?"
  1279.     }
  1280.     if {[askyesno $text] == "yes"} {
  1281.         set path [getfile "Locate new helper:"]
  1282.         set nsig [getFileSig $path]
  1283.         set app [nameFromAppl $nsig]
  1284.         if {$app != $path} {
  1285.             alertnote "Appl sig '$nsig' is mapped to '$app', not '$path'. Remove the former, or rebuild your desktop."
  1286.             return
  1287.         }
  1288.         if {[askyesno "Are you sure you want to set $sig to '$nsig' (mapped to '$app')?"] == "yes"} {
  1289.             set $sig $nsig
  1290.             lappend modifiedVars $sig
  1291.         }
  1292.     }
  1293. }
  1294. #===============================================================================
  1295.  
  1296. proc dumpNamedMacro {} {
  1297.     global macroArr
  1298.     set name [listpick -p "Macro name?" [array names macroArr]]
  1299.     regsub -all ";\r" $macroArr($name) "\r" text
  1300.     insertText $text
  1301. }
  1302.  
  1303.  
  1304. proc nameLastMacro {} {
  1305.     global macroArr modifiedArrVars
  1306.     set name [prompt "Macro name?" ""]
  1307.     regsub macroName [keyboardMacro] $name macro
  1308.     regsub -all "\r" $macro ";\r" macro
  1309.     eval $macro
  1310.     addMenuItem KbdMacros $name
  1311.     set macroArr($name) $macro
  1312.     lappend modifiedArrVars macroArr
  1313.     rebuildMacroMenu
  1314. }
  1315.  
  1316. proc deleteNamedMacro {} {
  1317.     global macroArr modifiedArrVars
  1318.     
  1319.     set which [listpick -p "Delete which macro?" [lsort [array names macroArr]]]
  1320.     unset macroArr($which)
  1321.     lappend modifiedArrVars macroArr
  1322.     rebuildMacroMenu
  1323. }
  1324.  
  1325. proc rebuildMacroMenu {} {
  1326.     global macroArr
  1327.     
  1328.     set l {}
  1329.     foreach f [lsort [array names macroArr]] {
  1330.         eval $macroArr($f)
  1331.         lappend l $f
  1332.     }
  1333.     eval menu -m -n macros [list $l]
  1334. }
  1335.